package com.blaze.framework.core.security.util;

import com.blaze.framework.core.util.constants.TokenConstants;
import com.blaze.framework.core.util.domain.TokenInfo;
import com.blaze.framework.core.util.exception.CheckedException;
import com.blaze.framework.core.util.json.JsonUtil;
import com.blaze.framework.core.util.uitls.AssertUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;

import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * Token util
 *
 * @author created by Zhou Zongbo on 2025/5/30.
 */
@Slf4j
public class TokenUtil {
    private TokenUtil() {

    }

    /**
     * 解析token信息
     *
     * @param token token
     * @return token信息
     */
    public static TokenInfo parseToken(String token) {
        AssertUtil.isNotBlank(token, "令牌不能为空");
        AssertUtil.isTrue(token.startsWith(TokenConstants.AUTHORIZATION_BEARER), "令牌格式错误");
        String tokenBody = token.substring(7);

        try {
            SignedJWT jwt = SignedJWT.parse(tokenBody);
            JWTClaimsSet jwtClaimsSet = jwt.getJWTClaimsSet();
            TokenInfo.TokenInfoBuilder builder = TokenInfo.builder();
            builder.userId(getClaimAsString(jwtClaimsSet, TokenConstants.TOKEN_USER_ID));
            builder.username(getClaimAsString(jwtClaimsSet, TokenConstants.TOKEN_USER_NAME));
            builder.expireTime(getClaimAsDate(jwtClaimsSet, TokenConstants.TOKEN_EXPIRE_TIME));
            builder.roles(getRoles(jwtClaimsSet));
            return builder.build();
        } catch (ParseException e) {
            throw new CheckedException("授权证书解析异常", e);
        }
    }

    /**
     * 从jwt中获取参数
     *
     * @param jwtClaimsSet jwtClaimsSet
     * @param parameter    parameter
     * @return 参数值
     */
    private static String getClaimAsString(JWTClaimsSet jwtClaimsSet, String parameter) {
        if (Objects.isNull(jwtClaimsSet)) {
            return StringUtils.EMPTY;
        }

        try {
            return jwtClaimsSet.getClaimAsString(parameter);
        } catch (ParseException e) {
            log.error("getClaimAsString从jwt中获取参数异常", e);
            return null;
        }
    }


    /**
     * 从jwt中获取参数
     *
     * @param jwtClaimsSet jwtClaimsSet
     * @param parameter    parameter
     * @return 参数值
     */
    private static LocalDateTime getClaimAsDate(JWTClaimsSet jwtClaimsSet, String parameter) {
        if (Objects.isNull(jwtClaimsSet)) {
            return null;
        }

        try {
            return jwtClaimsSet.getDateClaim(parameter).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        } catch (ParseException e) {
            log.error("getClaimAsString从jwt中获取参数异常", e);
            return null;
        }
    }

    /**
     * 从token中解析角色数据
     *
     * @param jwtClaimsSet jwtClaimsSet
     * @return 权限标识集合
     */
    @NonNull
    private static Set<String> getRoles(JWTClaimsSet jwtClaimsSet) {
        try {
            Map<String, Object> realAccess = jwtClaimsSet.getJSONObjectClaim(TokenConstants.TOKEN_REALM_ACCESS);
            if (MapUtils.isEmpty(realAccess)) {
                return Collections.emptySet();
            }

            List<String> roles = JsonUtil.mapToList(realAccess, TokenConstants.TOKEN_ROLES, new TypeReference<>() {
            });
            return new HashSet<>(roles);
        } catch (ParseException e) {
            log.error("getRoles从jwt中获取角色参数异常", e);
            return Collections.emptySet();
        }
    }
}
